/* to compile in Linux, type:   gcc -o concurrentserver concurrentserver.c -lpthread */

#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

void * serverthread(void * parm);       /* thread function prototype    */

#define MAXBUFLEN					100
#define DEFAULTPORT       35555

struct thread_data
{
   int	thread_id;
   int  len;
   char *message;
};

main (int argc, char *argv[])
{
     struct   hostent   *ptrh;     /* pointer to a host table entry */
     struct   sockaddr_in sad;     /* structure to hold server's address */
     struct   sockaddr_in cad;     /* structure to hold client's address */
     int      sd, sd2;             /* socket descriptors */
     int      port;                /* protocol port number */
     int      alen;                /* length of address */
     pthread_t  tid;               /* variable to hold thread ID */
     char buf[MAXBUFLEN];
		 int n;	
     int thd_count = 0;

     memset((char  *)&sad,0,sizeof(sad));
     sad.sin_family = AF_INET;           
     sad.sin_addr.s_addr = INADDR_ANY;   

     if (argc > 1)                        
        port = atoi (argv[1]); 
     else
        port = DEFAULTPORT;

     if (port > 0)
        sad.sin_port = htons((u_short)port);
     else { 
       cerr << "Bad port number " << argv[1] <<endl;
       exit (1);
     }

     /* Create a socket */
     sd = socket (PF_INET, SOCK_DGRAM, 0);
     if (sd < 0) {
       cerr << "Socket creation failed << endl";
       exit(1);
     }

     /* Bind a local address to the socket */
     if (bind(sd, (struct sockaddr *)&sad, sizeof (sad)) < 0) {
         cerr << "Bind failed " << endl;
         exit(1);
     }

     alen = sizeof(struct sockaddr);

     /* Main server loop - accept and handle requests */
     cout << "Server ready! Listening at: " << inet_ntoa(sad.sin_addr) << " port: " << port<< endl;

     while (1) {
       cout<< "SERVER: Waiting for messages ... " << endl;
       if ((n = recvfrom(sd, buf, MAXBUFLEN-1, 0, 
                         (struct sockaddr *)&cad, (socklen_t *)&alen)) < 0) {
	       cerr << "Accept failed" << endl;
         exit (1);
	     }
   	   
      cout << "Server: Got " << n << " bytes! creating a thread..." << endl;
			
      thread_data param;
      param.thread_id = thd_count;
      param.message = buf;
      param.len = n;
 
      thd_count++;           
      if ( pthread_create(&tid, NULL, serverthread, (void *) &param ) !=0 ){
          cerr << "Error creating thread!" << endl;
      }
     
     }
     
     close(sd);
}


void * serverthread(void * parm)
{
   int i, len;
   struct thread_data * d = (struct thread_data *) parm;
   char * msg = d->message; 
  len = d->len;
	cout << "Size of message recvd: " << len << endl; 
	for ( i=0; i < len; i++){
     sleep(5);
		 cout << "Server Thread " << d->thread_id << ": Spelling(" << msg << ")... " << msg[i]<< endl; 
   }
   
  pthread_exit(0);
}    
